/*
 * Copyright (C) 2021 XRADIO TECHNOLOGY CO., LTD. All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *    1. Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the
 *       distribution.
 *    3. Neither the name of XRADIO TECHNOLOGY CO., LTD. nor the names of
 *       its contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @addtogroup IotHardware
 * @{
 *
 * @brief Provides APIs for operating devices,
 * including flash, GPIO, I2C, PWM, UART, and watchdog APIs.
 *
 *
 *
 * @since 2.2
 * @version 2.2
 */
#include "iot_errno.h"
#include "iot_uart.h"
#include "driver/chip/hal_uart.h"

//#define UART_DMA_MODE
//#define UART_IT_MODE
#define UART_POLL_MODE

/**
 * @brief Configures a UART device with the port number specified by <b>id</b>
 * based on the basic and extended attributes.
 *
 *
 *
 * @param id Indicates the port number of the UART device.
 * @param param Indicates the pointer to the UART attributes.
 * @return Returns {@link IOT_SUCCESS} if the UART device is configured successfully;
 * returns {@link IOT_FAILURE} otherwise. For details about other return values, see the chip description.
 * @since 2.2
 * @version 2.2
 */
unsigned int IoTUartInit(unsigned int id, const IotUartAttribute *param)
{
	HAL_Status status = HAL_ERROR;
	UART_InitParam uart;

	if ((UART_ID)id >= UART_NUM) {
		printf("IoTUartInit id=%d error\r\n", id);
		return IOT_FAILURE;
	}

	if ((param->dataBits != IOT_UART_DATA_BIT_5) &&
	    (param->dataBits != IOT_UART_DATA_BIT_6) &&
	    (param->dataBits != IOT_UART_DATA_BIT_7) &&
	    (param->dataBits != IOT_UART_DATA_BIT_8)) {
		printf("IoTUartInit param->dataBits=%d error\r\n",
		       param->dataBits);
		return IOT_FAILURE;
	} else {
		switch (param->dataBits) {
		case IOT_UART_DATA_BIT_5:
			uart.dataBits = UART_DATA_BITS_5;
			break;

		case IOT_UART_DATA_BIT_6:
			uart.dataBits = UART_DATA_BITS_6;
			break;

		case IOT_UART_DATA_BIT_7:
			uart.dataBits = UART_DATA_BITS_7;
			break;

		case IOT_UART_DATA_BIT_8:
			uart.dataBits = UART_DATA_BITS_8;
			break;

		default:
			break;
		}
	}

	if ((param->stopBits != IOT_UART_STOP_BIT_1) &&
	    (param->stopBits != IOT_UART_STOP_BIT_2)) {
		printf("IoTUartInit param->stopBits=%d error\r\n",
		       param->stopBits);
		return IOT_FAILURE;
	} else {
		switch (param->stopBits) {
		case IOT_UART_STOP_BIT_1:
			uart.stopBits = UART_STOP_BITS_1;
			break;

		case IOT_UART_STOP_BIT_2:
			uart.stopBits = UART_STOP_BITS_2;
			break;

		default:
			break;
		}
	}

	if ((param->parity != IOT_UART_PARITY_NONE) &&
	    (param->parity != IOT_UART_PARITY_ODD) &&
	    (param->parity != IOT_UART_PARITY_EVEN)) {
		printf("IoTUartIniparam->parity=%d error\r\n", param->parity);
		return IOT_FAILURE;
	} else {
		switch (param->parity) {
		case IOT_UART_PARITY_NONE:
			uart.parity = UART_PARITY_NONE;
			break;

		case IOT_UART_PARITY_ODD:
			uart.parity = UART_PARITY_ODD;
			break;

		case IOT_UART_PARITY_EVEN:
			uart.parity = UART_PARITY_EVEN;
			break;

		default:
			break;
		}
	}

	uart.baudRate = param->baudRate;
	uart.isAutoHwFlowCtrl = 0;

	status = HAL_UART_Init((UART_ID)id, &uart);
	if (status != HAL_OK) {
		printf("uart init error %d\n", status);
		return IOT_FAILURE;
	}

#if (defined(UART_DMA_MODE))
	HAL_Status status = HAL_ERROR;

	status = HAL_UART_EnableTxDMA((UART_ID)id);
	if (status != HAL_OK) {
		HAL_UART_DeInit((UART_ID)id);
		return IOT_FAILURE;
	}

	status = HAL_UART_EnableRxDMA((UART_ID)id);
	if (status != HAL_OK) {
		HAL_UART_DeInit((UART_ID)id);
		return IOT_FAILURE;
	}
#endif

	return IOT_SUCCESS;
}

/**
 * @brief Reads a specified length of data from a UART device with the port number specified by <b>id</b>.
 *
 *
 *
 * @param id Indicates the port number of the UART device.
 * @param data Indicates the pointer to the start address of the data to read.
 * @param dataLen Indicates the number of bytes to read.
 * @return Returns the number of bytes read if the operation is successful; returns <b>-1</b> otherwise.
 * @since 2.2
 * @version 2.2
 */
int IoTUartRead(unsigned int id, unsigned char *data, unsigned int dataLen)
{
	int ret = -1;

	if ((UART_ID)id >= UART_NUM) {
		printf("IoTUartRead id=%d error\r\n", id);
		return IOT_FAILURE;
	}

#if (defined(UART_POLL_MODE))
	ret = HAL_UART_Receive_Poll((UART_ID)id, data, dataLen, 1000);
#endif

#if (defined(UART_IT_MODE))
	ret = HAL_UART_Receive_IT((UART_ID)id, data, dataLen, 1000);
#endif

#if (defined(UART_DMA_MODE))
	ret = HAL_UART_Receive_DMA((UART_ID)id, data, dataLen, 1000);
#endif

	return ret;
}

/**
 * @brief Writes a specified length of data to a UART device with the port number specified by <b>id</b>.
 *
 *
 *
 * @param id Indicates the port number of the UART device.
 * @param data Indicates the pointer to the start address of the data to write.
 * @param dataLen Indicates the number of bytes to write.
 * @return Returns the number of bytes written if the operation is successful; returns <b>-1</b> otherwise.
 * @since 2.2
 * @version 2.2
 */
int IoTUartWrite(unsigned int id, const unsigned char *data,
		 unsigned int dataLen)
{
	int ret = -1;
	if ((UART_ID)id >= UART_NUM) {
		printf("IoTUartWrite id=%d error\r\n", id);
		return IOT_FAILURE;
	}

#if (defined(UART_POLL_MODE))
	ret = HAL_UART_Transmit_Poll((UART_ID)id, (uint8_t *)data, dataLen);
#endif

#if (defined(UART_IT_MODE))
	ret = HAL_UART_Transmit_IT((UART_ID)id, (uint8_t *)data, dataLen);
#endif

#if (defined(UART_DMA_MODE))
	ret = HAL_UART_Transmit_DMA((UART_ID)id, (uint8_t *)data, dataLen);
#endif
	return ret;
}

/**
 * @brief Deinitializes a UART device.
 *
 * @param id Indicates the port number of the UART device.
 * @return Returns {@link IOT_SUCCESS} if the UART device is deinitialized;
 * returns {@link IOT_FAILURE} otherwise. For details about other return values, see the chip description.
 * @since 2.2
 * @version 2.2
 */
unsigned int IoTUartDeinit(unsigned int id)
{
	HAL_Status status = HAL_ERROR;

	if ((UART_ID)id >= UART_NUM) {
		printf("IoTUartDeinit id=%d error\r\n", id);
		return IOT_FAILURE;
	}

#if (defined(UART_DMA_MODE))
	status = HAL_UART_DisableTxDMA((UART_ID)id);
	if (status != HAL_OK) {
		printf("uart TX disenable DMA error %d\n", status);
	}

	status = HAL_UART_DisableRxDMA((UART_ID)id);
	if (status != HAL_OK) {
		printf("uart RX disenable DMA error %d\n", status);
	}
#endif

	status = HAL_UART_DeInit((UART_ID)id);
	if (status != HAL_OK) {
		printf("uart deinit error %d\n", status);
		return IOT_FAILURE;
	}

	return IOT_SUCCESS;
}

/**
 * @brief Sets flow control for a UART device with the port number specified by <b>id</b>.
 *
 *
 *
 * @param id Indicates the port number of the UART device.
 * @param flowCtrl Indicates the flow control parameters, as enumerated in {@link IotFlowCtrl}.
 * @return Returns {@link IOT_SUCCESS} if flow control is set successfully;
 * returns {@link IOT_FAILURE} otherwise. For details about other return values, see the chip description.
 * @since 2.2
 * @version 2.2
 */
unsigned int IoTUartSetFlowCtrl(unsigned int id, IotFlowCtrl flowCtrl)
{
	return IOT_SUCCESS;
}

/** @} */
